Skip to content

Cursor/multi event support 508c - #10

Open
RayFernando1337 wants to merge 33 commits into
mainfrom
cursor/multi-event-support-508c
Open

Cursor/multi event support 508c#10
RayFernando1337 wants to merge 33 commits into
mainfrom
cursor/multi-event-support-508c

Conversation

@RayFernando1337

@RayFernando1337 RayFernando1337 commented Aug 17, 2026

Copy link
Copy Markdown
Owner

LGTM BRO


Note

Medium Risk
Multi-event changes the data model, auth routes, and host/submission rules; misconfigured featured event or HOST_EMAILS could block hosts or split traffic across nights. The agent skill bulk add is docs-only for runtime.

Overview
Multi-event nights replace the single hard-coded night in lib/content.ts. Convex now owns events, settings (featured night), and submissions scoped by eventId, with per-night capacity and guest copy. Public routes add /e/[slug], apply, and board; /, /apply, and /board follow the featured event. /host becomes a nights desk and /host/[slug] triages one lineup; Clerk middleware extends to /e/*/apply. Landing, apply, and board pages delegate to shared event-aware components.

Agent and styling tooling adds the full .agents/skills/convex-* skill pack, .cursor/mcp.json for the Convex MCP, Convex AI blocks in AGENTS.md / CLAUDE.md, shadcn/tw-animate tokens in globals.css, and dev harness pages (guest copy/board, header IA) with a Convex-only layout when Clerk is missing on /harness.

Docs describe HTW as the featured night, slug URLs for room QRs, and Convex deploy notes for preview + new functions.

Reviewed by Cursor Bugbot for commit 6b5023f. Bugbot is set up for automated code reviews on this repo. Configure here.

cursoragent and others added 2 commits August 17, 2026 21:00
Hosts post a night from /host. Each night gets /e/[slug] for the room QR.
/, /apply, and /board still serve the featured night so the house QR keeps working.

Co-authored-by: smile <smile@rayfernando.com>
Keep the userId and selectedAt notes. Those names still hide Clerk and board-order rules.

Co-authored-by: smile <smile@rayfernando.com>
@vercel

vercel Bot commented Aug 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
aios-lightning Ready Ready Preview Sep 1, 2026 6:45am UTC

Request Review

devin-ai-integration[bot]

This comment was marked as resolved.

cursor[bot]

This comment was marked as resolved.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Risk: high. Left a non-blocking comment and did not approve: Cursor Bugbot reported unresolved findings, and this multi-event schema/API change is above the medium approval threshold. Human review is needed; no additional reviewers were assigned.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

Stick the house event from settings rather than the open-event fallback, keep submissions.eventId optional so existing rows can deploy, build /e/[slug] nav hrefs from the known slug while loading, and trim hyphens after slug truncation so long names still create.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Risk: high. Left a non-blocking comment and did not approve: Cursor Bugbot completed cleanly with prior findings resolved, but this multi-event schema and host/apply/board change is above the medium approval threshold. Human review is needed; no reviewers were assigned.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

devin-ai-integration[bot]

This comment was marked as resolved.

The Vercel preview was calling events:bySlug against a backend that
never received this branch. Required eventId on existing submissions
would also block a cloud deploy. Keep that field optional until
ensureSeed backfills, persist the featured pointer in settings, and
install Convex AI files plus the ESLint plugin so local convex dev
can push and surface function errors.

Co-authored-by: smile <smile@rayfernando.com>
cursor[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Risk: high. Left a non-blocking comment and did not approve: Cursor Bugbot skipped on this head, and this multi-event schema and host/apply/board change is above the medium approval threshold. Human review is needed; no reviewers were assigned.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

Add @convex-dev/eslint-plugin to package-lock.json so npm ci matches
package.json. Keep cloud-agent-start.sh watching Convex with the same
Clerk placeholder as install. Drop unused submissions by_user and
by_status indexes.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Risk: high. Left a non-blocking comment and did not approve: Cursor Bugbot completed cleanly on this head, but this multi-event schema and host/apply/board change is above the medium approval threshold. Human review is needed; no reviewers were assigned.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

devin-ai-integration[bot]

This comment was marked as resolved.

Orphan submissions now attach to a fallback event in bounded batches
and skip or merge on (eventId, userId) collisions. New nights
interpolate the chosen slot count, reserved slugs suffix instead of
throwing, and clipboard failures show a selectable URL.

Co-authored-by: smile <smile@rayfernando.com>
cursor[bot]

This comment was marked as resolved.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Risk: high. Left a non-blocking comment and did not approve: Cursor Bugbot skipped on this head, and this multi-event schema and host/apply/board change is above the medium approval threshold. Human review is needed; no reviewers were assigned.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

When attaching a selected orphan, demote it to shortlisted if the night is already full, and do not copy selected status over a non-selected row for the same user.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 new potential issues.

View 2 additional findings in Devin Review.

Open in Devin Review

Comment thread convex/events.ts Outdated
Comment on lines +154 to +171
const events = await ctx.db.query("events").order("desc").collect();
const featuredId = await getStoredFeaturedEventId(ctx);

const rows = [];
for (const event of events) {
const submissions = await ctx.db
.query("submissions")
.withIndex("by_event_status", (q) => q.eq("eventId", event._id))
.collect();
const counts = {
submitted: 0,
shortlisted: 0,
selected: 0,
rejected: 0,
};
for (const submission of submissions) {
counts[submission.status] += 1;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Host page reads every application of every night on each load

Every application row of every night is loaded in full (.collect() inside the per-event loop at convex/events.ts:159-162, plus the unbounded event scan at convex/events.ts:154) just to show per-night counts, so the host page gets slower and eventually fails as history accumulates.
Impact: Once enough nights and applications exist, opening the host pages becomes slow and can hit Convex read limits, blocking triage.

Unbounded per-event scan, and it runs on the triage page too

convex/events.ts:149-182 collects all events, then for each event collects all of its submissions through by_event_status with no bound. convex/_generated/ai/guidelines.md (mandatory reading per AGENTS.md) states: "Never an unbounded .collect() on a table that can grow — use .withIndex(...) and .paginate(...)/.take(n)" and "Never use .collect().length to count rows".

It is not only the desk: components/HostEventBody.tsx:24 calls api.events.listForHost on every /host/[slug] load merely to derive the boolean featured flag (components/HostEventBody.tsx:38-46), which could be read from settings alone.

Prompt for agents
convex/events.ts listForHost collects every event and then every submission of each event to compute status counts, an unbounded N+1 read that violates the repo's mandated Convex guidelines (no unbounded .collect(), no .collect().length counting). It is also fetched by components/HostEventBody.tsx just to learn whether the event is featured. Consider (a) exposing a cheap query that returns only the stored featured event id for the triage page, and (b) bounding or denormalizing the per-event counts (e.g. maintain counters on the event document in submissions.submit/setStatus, or use .take(n) with a cap and label it as such).
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved: Host counts use bounded .take() in convex/lib/counts.ts (countSelected / countByStatus). events.listForHost does not .collect() the submissions table. Orphan backfill is paginated and gated by submissionEventBackfillDone.

Comment thread scripts/cloud-agent-install.sh Outdated
Comment on lines +33 to +36
# auth.config.ts always reads this. A placeholder lets --once push public
# functions when Clerk is unset. Gated routes still need the real issuer.
bunx convex env set CLERK_JWT_ISSUER_DOMAIN \
"${CLERK_JWT_ISSUER_DOMAIN:-https://unused.clerk.accounts.dev}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Setup script can overwrite a working sign-in configuration with a placeholder

The Clerk issuer value on the Convex deployment is unconditionally overwritten with a dummy address (convex env set CLERK_JWT_ISSUER_DOMAIN "${CLERK_JWT_ISSUER_DOMAIN:-https://unused.clerk.accounts.dev}" at scripts/cloud-agent-install.sh:35-36) whenever the shell variable happens to be unset, so a deployment that was already configured silently stops accepting sign-ins.
Impact: Re-running the install script in a shell without the Clerk variable can leave everyone signed out with no error message.

Behavior change versus the previous guard

Before this PR the script exited early when CLERK_JWT_ISSUER_DOMAIN was unset (removed lines 27-31), leaving whatever value the deployment already had. Now it always writes, and the fallback is a non-existent issuer. convex env set targets whatever deployment CONVEX_DEPLOYMENT resolves to, which for a developer running the script locally can be a real dev deployment rather than the anonymous local backend. With a wrong issuer, convex/auth.config.ts validation fails and the app is silently always-signed-out.

A safer shape is to only write the placeholder when the deployment has no value yet, or only in anonymous/local mode.

Prompt for agents
scripts/cloud-agent-install.sh now always runs `convex env set CLERK_JWT_ISSUER_DOMAIN` with a placeholder fallback, whereas it previously skipped the Convex push entirely when the variable was unset. If the resolved deployment is a real (cloud dev) deployment that already had the correct Clerk Frontend API URL, the placeholder clobbers it and sign-in silently fails. Gate the placeholder write so it only applies when the deployment has no value yet (or only when running against the anonymous local backend), and keep the real value untouched otherwise.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved: scripts/cloud-agent-install.sh writes https://placeholder.invalid only when Clerk is unset and the stored issuer is missing or the old unused.clerk placeholder. A real issuer is preserved.

Comment thread convex/events.ts
Comment on lines +347 to +365
export const ensureSeed = mutation({
args: {},
returns: v.union(v.id("events"), v.null()),
handler: async (ctx) => {
await requireHost(ctx);

const event = await resolveSeedEvent(ctx);
if (event === null) {
return null;
}

if ((await getStoredFeaturedEventId(ctx)) === null) {
await setFeaturedEvent(ctx, event._id);
}

await continueOrphanBackfill(ctx, event._id, null);
return event._id;
},
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Existing lineup and landing page go blank after deploy until a host signs in

An already-running site loses its public running order and landing copy (public pages resolve a night through resolveEvent at convex/lib/eventLookup.ts:47-55, which finds nothing until the host-only ensureSeed at convex/events.ts:347-365 runs) before any night exists, so attendees see an empty board.
Impact: After deploying this change to a live site, the projector board and landing page show "no night" until a host signs in and opens the host page.

Why the recovery path is host-gated and client-triggered

On an existing deployment, events and settings are empty and every submissions row has eventId === undefined. submissions.board (convex/submissions.ts:197-211) and events.bySlug therefore return [] / null, so /board shows the empty state and / renders components/EmptyEvent.tsx.

The only code path that creates the seed event and attaches legacy rows is events.ensureSeed, which calls requireHost and is invoked from a client effect in components/HostDesk.tsx:36-38. Until an allow-listed host signs in and mounts /host, no public page recovers, and submissions.setStatus also refuses the legacy rows (convex/submissions.ts:159-161).

A data migration that does not depend on an authenticated host visit (e.g. a one-shot internal mutation run at deploy time) would remove the window.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved: events.ensurePublicSeed exists and only writes when the events table is empty. EmptyEvent mounts SeedIfEmpty. Public landing, board, and apply no longer wait for a host to open /host.

cursor[bot]

This comment was marked as resolved.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Risk: high. Left a non-blocking comment and did not approve: Cursor Bugbot skipped on this head, and this multi-event schema, data migration, and host/apply/board change is above the medium approval threshold. Human review is needed; no reviewers were assigned.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

devin-ai-integration[bot]

This comment was marked as resolved.

Public empty pages now run the one-shot seed and orphan backfill so
the landing and board come back after deploy without a host login.
Orphan merge keeps the higher status and the newer copy, and demotes
to shortlisted when the night is full. Capacity edits rewrite the
house rules. Install no longer clobbers a real Clerk issuer.

Co-authored-by: smile <smile@rayfernando.com>
guestCopy lives on the event. ApplyForm, the board heading, and
the house brand read it. HTW labels are bot-demo. SF keeps the
old lightning labels. Same submission fields.

Co-authored-by: Ray Fernando <RayFernando1337@users.noreply.github.com>
cursor[bot]

This comment was marked as resolved.

cursor[bot]

This comment was marked as resolved.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Risk: high. Left a non-blocking comment and did not approve: Cursor Bugbot skipped on this head and left unresolved findings, and this multi-event schema, data migration, and host/apply/board change is above the medium approval threshold. Human review is needed; no reviewers were assigned.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

devin-ai-integration[bot]

This comment was marked as resolved.

/harness/guest reads the featured night from Convex and renders
the apply labels plus BoardList. Production still shows the setup
checklist when Clerk keys are missing. internalSeedDemoTalk puts
one selected row on a night so the board is not empty.

Co-authored-by: Ray Fernando <RayFernando1337@users.noreply.github.com>
devin-ai-integration[bot]

This comment was marked as resolved.

cursor[bot]

This comment was marked as resolved.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Risk: high. Left a non-blocking comment and did not approve; Cursor Bugbot finished as skipped, and this change spans auth, host gating, schema, and multi-event routing. No reviewers were assigned; human review is needed.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

headers() reads incoming request headers, so x-pathname must be
applied via NextResponse.next({ request: { headers } }) for /harness
to skip SetupNotice when Clerk is missing.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Risk: high. Left a non-blocking comment and did not approve; Cursor Bugbot finished as skipped, and this multi-event schema, auth, and host/apply/board change is above the medium approval threshold. No reviewers were assigned; human review is needed.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

cursoragent and others added 2 commits August 31, 2026 21:32
ensureSeed no longer re-archives SF or rewrites featuredEventId after
HTW staging. Missing aios-sf-lightning is a no-op instead of archiving
the first events row. Host triage paginates newest-first so every
application stays reachable.

Co-authored-by: Ray Fernando <RayFernando1337@users.noreply.github.com>
Co-authored-by: Ray Fernando <RayFernando1337@users.noreply.github.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Risk: high. Left a non-blocking comment and did not approve; Cursor Bugbot completed with no unresolved findings, but this multi-event schema, auth, and host/apply/board change is above the medium approval threshold. No reviewers were assigned; human review is needed.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

Guests see Board plus My slot or Sign in. Hosts get one Desk link.
Main night, Public, Triage, and the Host chip leave the global bar.
Each item is a padded square hit. The glass row does not wrap.

Co-authored-by: Ray Fernando <RayFernando1337@users.noreply.github.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Risk: high. Left a non-blocking comment and did not approve; Cursor Bugbot completed with no new findings, but this multi-event schema, auth, and host/apply/board change is above the medium approval threshold. No reviewers were assigned; human review is needed.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 new potential issues.

11 flags not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)

Devin Review

Comment thread convex/events.ts
Comment thread convex/schema.ts
room: v.string(),
capacity: v.number(),
dryRun: v.string(),
heroImage: v.string(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟨 Remote image URLs lack validation

heroImage accepts arbitrary strings and reaches a browser CSS URL. Imported or future editable event data can make every visitor request an attacker-controlled resource.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved: Dismissed. Hosts cannot set heroImage from the UI. events.create copies SITE.heroImage. events.update has no heroImage argument. Seeds use the house path. No arbitrary URL input, so no extra validator.

@cursor

cursor Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Header IA proof on 95cbf61. Local harness (/harness/header) because this environment has no Clerk session. Exact viewports via headless Chrome.

Guest 390: Board, My slot, square avatar. One glass row. No Main night in the bar.

Guest header at 390px

Host 390: Desk, Board, My slot, square avatar. One glass row. No Host chip.

Host header at 390px

Guest 1280: ticket + event line on the left. Bar is Board, My slot, avatar.

Guest header at 1280px

Host 1280: same left chrome. Bar is Desk, Board, My slot, avatar.

Host header at 1280px

resolveEvent treats phase archived as not found, so /e/[slug],
apply, and board stay off the guest surface. Hosts still load
those nights through hostBySlug and listForHost. Rows stay in
the table.

Co-authored-by: Ray Fernando <RayFernando1337@users.noreply.github.com>
cursor[bot]

This comment was marked as resolved.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Risk: high. Left a non-blocking comment and did not approve; Cursor Bugbot finished as skipped and reported an unresolved finding, and this multi-event schema, auth, and host/apply/board change is above the medium approval threshold. No reviewers were assigned; human review is needed.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

Archive only takes a night off / and the public picker.
resolveEvent still returns archived events by slug so /e/[slug],
apply, and board keep working for printed QRs and host preview.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Risk: high. Left a non-blocking comment and did not approve; Cursor Bugbot completed successfully with no unresolved findings, but this multi-event schema, auth, and host/apply/board change is above the medium approval threshold. No reviewers were assigned; human review is needed.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants